9.9更新: 更正呼叫堆疊的內部為 stack frame。
(提醒:文中的執行環境都是browser(chrome))
今天要解釋JS的Event Loop事件循環,分成上下兩篇,這篇還不會講到Event Loop本身!!
上篇:
下篇:
在之前的文章 JavaScript的執行階段: Execution Context 有提到,在execution phase裡(綠色框框),都是依照 Call Stack的方式執行script。
↑execution phase裡(綠色框框)
這邊要先提到Stack的概念:
資料結構是指電腦儲存資料的方式,分成很多種,而「Stack(堆疊)」是一種資料結構。
Stack的特色是 後進先出(Last-in-First-out, LIFO)。
可以想像Stack是一種由下而上堆疊起來的frame(Function calls from a stack of frames.):
到這邊應該對Stack比較有概念了,接下來要開始說明Call Stack。
讓我們先看到例子:
function a(){
function b(){
function c(){
console.log('This is c()');
}
c();
console.log('This is b()');
}
b();
console.log('This is a()');
}
a();
然後他的console會是這樣:
This is c()
This is b()
This is a()
在execution phase裡,決定事件處理的順序是這麼做的:
呼叫a(): 將a放入call stack,
開始讀取function a()裡的程式碼,讀到b(),b也放入call stack。
開始讀取function b()裡的程式碼,讀到c(),c也放入call stack。
執行console.log('This is c()');
;c()執行完成,從call stack移除c。
執行console.log('This is b()');
;b()執行完成,從call stack移除b。
執行console.log('This is a()');
;a()執行完成,從call stack移除a。
a()執行完畢,call stack被清空。
→ 想看動態的可以看這裡,gif版(imgur)
→ 也可以把程式碼丟到這看效果(非常之厲害的視覺化工具)【loupe】
到這邊劃個重點:
每調用一次函式,函式都會被放進Call Stack。
只要正在執行的函式裡調用了新的函式,新函式也會被放入Call Stack。
函式執行完成,會被清出,直到call stack被清空。
再讓我們看一個例子:
function f(){
f();
}
f();
可想而知,執行f()
時,call stack可能會長這樣:
這種超過Call Stack容量的情況,稱作Stack overflow。
很遺憾的,這個函式會呼叫自己一輩子,這代表我們永遠看不到這個函式執行完的結果。還有電腦可能被燒壞
如果想要解決這個問題,最常見的方法就是使用非同步函式 Asynchronous function。
當跑一段程式碼(script),瀏覽器(bowser)會將執行結果直接回傳,這樣的執行方式叫做"同步"。
(包含文內的例子(還有至今為止的文章),執行方式都是同步的。)
由於JS是單執行緒(thread),程式碼的執行順序當下同一時間只會處理一件事。所以只要有一段程式碼還沒有執行完成,其他的任務就都會停擺,這樣會造成時間上的浪費。
JavaScript 在傳統意義上是跑在一條單執行緒。即便你的電腦有多顆核心,也只能在 JavaScript 上面跑一條執行緒來完成任務,這一條執行緒我們稱為主執行緒( main thread )。
為了解決這個問題,便有了非同步程式設計。
非同步(Asynchronous,又稱異步)則與同步相反,在指定時間或情形,才處理和接收訊息,而非在讀到程式碼時直接執行。
可以看到MDN對非同步的介紹:
Javascript 基本上是一個同步性的、阻塞的,且是跑在單一執行緒的程式語言,也就是在同一時間只能執行一個操作。但是 瀏覽器所定義的函式和 API 允許我們註冊一個不該被同步執行的函式,且這個函式應該在某些事件發生時需要非同步的被呼叫 (到達指定的時間、使用者透過滑鼠互動,或者取得透過從網路所取到的資料)。這代表你可以讓你的程式碼在同時間做一些事情而不需暫停或阻塞你的主執行緒。
如果能將其他任務交給其他處理器來執行,並確認任務何時完成,就可以緩解浪費時間、效率不佳的問題。
那麼下一篇就會講到非同步函式的執行,然後就可以完整解釋Event Loop了。
【如內文有誤還請不吝指教>< 謝謝閱覽至此的各位:D】
參考資料:
-----正文結束-----